import 'package:flutter/foundation.dart';
import 'package:petitparser/petitparser.dart';
import 'package:test/test.dart' hide predicate;
import 'package:test/test.dart' as test show predicate;


/// Returns a [Matcher] that asserts two parsers are structurally equivalent.
Matcher isParserEqual<T>(Parser<T> parser) =>
    test.predicate((actual) => actual is Parser<T> && actual.isEqualTo(parser), 'structurally equal');

/// Returns a [Matcher] that asserts the context under test is a [Success].
/// Optionally also asserts [position] and [value].
TypeMatcher<Success<T>> isSuccessContext<T>({
  dynamic position = anything,
  dynamic value = anything,
}) =>
    isA<Success<T>>()
        .having((context) => context.value, 'value', value)
        .having((context) => context.position, 'position', position);

T isParseSuccess<T>(
  Parser<T> parser,
  String input, {
  dynamic position,
}) {
  var parseResult = parser.parse(input);
  if (parseResult.isSuccess) {
    var value = parseResult.value;
    var fastParseResult = parser.fastParseOn(input, 0);
    var acceptResult = parser.accept(input);
    var allMatchesResult = parser.allMatches(input).first;

    if (fastParseResult == (position ?? input.length) && acceptResult == true) {
      if ((allMatchesResult.runtimeType == List<dynamic>) && (value.runtimeType == List<dynamic>)) {
        // allMatchesResult.setEquals(value);
        if (listEquals(allMatchesResult as List?, value as List?)) {
          return value;
        }
      } else if (allMatchesResult == value) {
        return value;
      }
    }
    print(
        "fastParseResult:$fastParseResult\n input.length:${input.length}\n acceptResult:$acceptResult\n allMatchesResult:$allMatchesResult value:$value ");
    print(
        "fastParseResult:${fastParseResult == (position ?? input.length)}\n acceptResult:${acceptResult == true}\n allMatchesResult:${allMatchesResult == value}");
    print("fastParseResult:${allMatchesResult.runtimeType}--${allMatchesResult.runtimeType == List<String>}");
  }

  throw Exception('Parse failed.');
}
bool isFailureContext<T>(Failure<T> context, {dynamic position = anything, dynamic message = anything}) {
  return context.message == message && context.position == position;
}

bool isParseFailure<T>(Parser<T> parser, String input, {dynamic position = 0, dynamic message = anything}) {
  return parser.parse(input) is Failure<T> &&
      isFailureContext(parser.parse(input) as Failure, position: position, message: message) &&
      parser.fastParseOn(input, 0) == -1 &&
      !parser.accept(input);
}

bool isPatternMatch(
  Match matchObj,
  String match, {
  dynamic start = anything,
  dynamic end = anything,
  dynamic groups = anything,
}) {
  if (matchObj.group(0) != match) {
    return false;
  }
  if (start != anything && matchObj.start != start) {
    return false;
  }
  if (end != anything && matchObj.end != end) {
    return false;
  }
  if (groups != anything) {
    var actualGroups = List.generate(matchObj.groupCount, (group) => matchObj.group(1 + group));
    if (!listEquals(actualGroups, groups)) {
      return false;
    }
  }
  return true;
}
